#define SIL_SIM_BASE_MF4_FILE

#include <iostream>
#include <cstdint>
#ifdef _WIN32
#include <Windows.h>
#else
#include <unistd.h>
#include <linux/limits.h>
#endif
#include <string>
#include <vector>
#include <fstream>

#include "VehicleMessage.h"

static std::vector<std::string> splitString(const std::string& text, const char delimiter)
{
	std::vector<std::string> result;

	std::string str = "";
	for(uint32_t i = 0U, size = text.size(); i < size; i++)
	{
		if(text[i] == delimiter)
		{
			result.push_back(str);
			str.clear();
		}
		else
		{
			str += text[i];
		}

		if(i + 1U == size)
		{
			if(false == str.empty())
			{
			result.push_back(str);
			}
			else
			{
				//do nothing
			}
		}
	}

	return result;
}

static void getFieldStrPos(const std::string& filed, const std::string& str, std::vector<std::string::size_type>& pos)
{
	std::string::size_type startPos = 0;

	pos.clear();
	while ((startPos = filed.find(str, startPos)) != std::string::npos)
	{
		pos.emplace_back(startPos);
		startPos += str.length();
	}
}

static bool isNumStr(const std::string& str)
{
	bool ret = true;

	for(uint32_t j = 0U; j < str.size(); j++)
	{
		if(0 != isalnum(str[j]))
		{
			if(0 != isalpha(str[j]))
			{
				ret = false;
				break;
			}
			else
			{
				//do nothing
			}
		}
		else
		{
			ret = false;
			break;
		}
	}

	return ret;
}

static bool getFieldArrayLength(const std::string& filed, std::vector<uint32_t>& arrayLength)
{
	bool ret = false;

	std::vector<std::string::size_type> leftPos;
	getFieldStrPos(filed, "[", leftPos);

	std::vector<std::string::size_type> rightPos;
	getFieldStrPos(filed, "]", rightPos);

	if(true == leftPos.empty() && true == rightPos.empty())
	{
		ret = true;
	}
	else if(leftPos.size() == rightPos.size())
	{
		arrayLength.clear(); 
		ret = true;
		for(uint32_t i = 0U; i < leftPos.size(); i++)
		{
			if(rightPos[i] > (leftPos[i] + 1U))
			{
				const std::string temp = filed.substr(leftPos[i] + 1U, rightPos[i] - (leftPos[i] + 1U));
				if(true == isNumStr(temp))
				{
					const int32_t num = std::stoi(temp);
					if(num >= 1)
					{
						arrayLength.emplace_back(static_cast<uint32_t>(num));
					}
					else
					{
						arrayLength.clear();
						ret = false;
						std::cout<<"file name = " << __FILE__ <<std::endl;
						std::cout<<"code line = " << std::dec << __LINE__<<std::endl;
						break;
					}
				}
				else
				{
					arrayLength.clear();
					ret = false;
					std::cout<<"file name = " << __FILE__ <<std::endl;
					std::cout<<"code line = " << std::dec << __LINE__<<std::endl;
					break;
				}
			}
			else
			{
				arrayLength.clear();
				ret = false;
				std::cout<<"file name = " << __FILE__ <<std::endl;
				std::cout<<"code line = " << std::dec << __LINE__<<std::endl;
				break;
			}
		}
	}
	else
	{
		ret = false;
		std::cout<<"file name = " << __FILE__ <<std::endl;
		std::cout<<"code line = " << std::dec << __LINE__<<std::endl;
	}

	return ret;
}

static std::string getFiledStr(const std::string& field)
{
	std::string ret;

	for(uint32_t i = 0U; i < field.size(); i++)
	{
		if(field[i] != '[')
		{
			ret += field[i];
		}
		else
		{
			break;
		}
	}

	return ret;
}

static std::vector<std::string> stringToSignal(const std::string& stringName)
{
	std::vector<std::string> ret;

	const std::vector<std::string> signalNameStr = splitString(stringName, '.');

	std::vector<std::vector<std::string>> signalNameVV;
	for(uint32_t i = 0U; i < signalNameStr.size(); i++)
	{
		std::vector<uint32_t> arrayLength;
		if(true == getFieldArrayLength(signalNameStr[i], arrayLength))
		{
			if(true == arrayLength.empty())
			{
				std::vector<std::string> signalNameV;
				signalNameV.push_back(signalNameStr[i]);

				signalNameVV.push_back(signalNameV);
			}
			else
			{
				std::vector<std::vector<std::string>> signalNameVVTemp;
				for(uint32_t j = 0U; j < arrayLength.size(); j++)
				{
					std::vector<std::string> signalNameVTemp;
					std::string prefix = "";
					if(0U == j)
					{
						prefix = getFiledStr(signalNameStr[i]);
					}
					else
					{
						//do nothing
					}

					for(uint32_t k = 0U; k < arrayLength[j]; k++)
					{
						signalNameVTemp.push_back(prefix + "[" + std::to_string(k) + "]");
					}
					signalNameVVTemp.push_back(signalNameVTemp);
				}

				std::vector<std::string> signalNameV;
				std::vector<std::string> signalNameVTemp;
				for(int32_t j = signalNameVVTemp.size() - 1; j >= 0; j--)
				{
					signalNameVTemp.clear();
					for(uint32_t k = 0U; k < signalNameVVTemp[j].size(); k++)
					{
						if(true == signalNameV.empty())
						{
							signalNameVTemp.push_back(signalNameVVTemp[j][k]);
						}
						else
						{
							for(uint32_t m = 0U; m < signalNameV.size(); m++)
							{
								signalNameVTemp.push_back(signalNameVVTemp[j][k] + signalNameV[m]);
							}
						}
					}
					signalNameV = signalNameVTemp;
				}
				signalNameVV.push_back(signalNameV);
			}
		}
		else
		{
			signalNameVV.clear();
			break;
		}
	}

	std::vector<std::string> retTemp;
	for(int32_t j = signalNameVV.size() - 1; j >= 0; j--)
	{
		std::string prefix = ".";
		if(0 == j)
		{
			prefix = "";
		}
		else
		{
			//do nothing
		}

		retTemp.clear();
		for(uint32_t k = 0U; k < signalNameVV[j].size(); k++)
		{
			if(true == ret.empty())
			{
				retTemp.push_back(prefix + signalNameVV[j][k]);
			}
			else
			{
				for(uint32_t m = 0U; m < ret.size(); m++)
				{
					retTemp.push_back(prefix + signalNameVV[j][k] + ret[m]);
				}
			}
		}
		ret = retTemp;
	}

	return ret;
}

static void addSimSignal(const std::string& signalName, std::vector<std::string>& simSigNames)
{
	std::vector<std::string> signalNameV = stringToSignal(signalName);

	for(uint32_t i = 0U; i < signalNameV.size(); i++)
	{
		simSigNames.push_back(signalNameV[i]);
	}
}

static void string_replace(std::string &s1, const std::string s2, const std::string s3)
{
	std::string::size_type pos = 0;
	std::string::size_type a = s2.size();
	std::string::size_type b = s3.size();
	while ((pos = s1.find(s2, pos)) != std::string::npos)
	{
		s1.replace(pos, a, s3);
		pos += b;
	}
}

// Values:
// - 0: 'array._1_._22_._333_'
// - 1: 'array[1] [22] [333]'
// - 2: 'array._1_22_333_''
// - 3: 'array_001__022__333_''
// - 4: 'array._001_._022_._333_'
// - 5: 'array._01_._22_._333_ (COFF compatible)'
// - 6: 'array_1_22_333_'
// - 7: 'array_1__22__333_'
// - 8: 'array.1.22.333'
static bool searchSignal(const std::string& str, const SimSignalData& simSignalData, uint32_t& groupIndex, uint32_t& signalIndex)
{
	struct SignalMes
	{
		std::string name;
		uint32_t groupIndex = 0U;
		uint32_t signalIndex = 0U;
	};

	static bool initFlag = false;
	static std::vector<SignalMes> signalMes;

	if(false == initFlag)
	{
		std::string filePath = "";
		#ifdef _WIN32
		char szFilePath[MAX_PATH + 1] = { 0 };
		GetModuleFileNameA(NULL, szFilePath, MAX_PATH);
		(strrchr(szFilePath, '\\'))[0] = 0;
		filePath = szFilePath;
		filePath += "/simSignalList.txt";
		#else
		char szFilePath[PATH_MAX];
		int32_t cnt = readlink("/proc/self/exe", szFilePath, PATH_MAX);
		if (cnt < 0 || cnt >= PATH_MAX)
		{
			//do nothing
		}
		else
		{
			for (int i = cnt - 1; i >= 0; i--)
			{
				if(szFilePath[i] == '/')
				{
					szFilePath[i] = '\0';
					break;
				}
				else
				{
					//do nothing
				}
			}
		}
		filePath = std::string(szFilePath);
		filePath += "/simSignalList.txt";
		#endif

		if(true == filePath.empty())
		{
			std::cout<< "file name = " << __FILE__ <<std::endl;
			std::cout<< "code line = " << std::dec << __LINE__ <<std::endl;
			std::cout<< "filePath invalid !" <<std::endl;
		}
		else
		{
			std::ifstream inFile(filePath, std::ios::in);
			if (true == inFile.is_open())
			{
				std::string readSignalMes;
				while(getline(inFile, readSignalMes))
				{
					if(true == readSignalMes.empty())
					{
						//do nothing
					}
					else
					{
						const std::string splitStr = "\t";
						std::string strs = readSignalMes + splitStr;
						std::string::size_type pos = strs.find(splitStr);
						uint32_t counter = 0U;
						SignalMes signalMesTemp;
						while(pos != strs.npos)
						{
							std::string str = strs.substr(0, pos);
							if(0U == counter)
							{
								signalMesTemp.name = str;
								counter++;
							}
							else if(1U == counter)
							{
								counter++;
							}
							else if(2U == counter)
							{
								counter++;
							}
							else if(3U == counter)
							{
								signalMesTemp.groupIndex = stoi(str);
								counter++;
							}
							else if(4U == counter)
							{
								signalMesTemp.signalIndex = stoi(str);
								counter++;
							}
							else
							{
								//do nothing
							}
							strs = strs.substr(pos + 1, strs.size());
							pos = strs.find(splitStr);
						}

						if(5U == counter)
						{
							signalMes.push_back(signalMesTemp);
						}
						else
						{
							std::cout<< "file name = " << __FILE__ <<std::endl;
							std::cout<< "code line = " << std::dec << __LINE__ <<std::endl;
							std::cout<< "error !" <<std::endl;
						}
					}
				}
				inFile.close();
			}
			else
			{
				std::cout<< "file name = " << __FILE__ <<std::endl;
				std::cout<< "code line = " << std::dec << __LINE__ <<std::endl;
				std::cout<< "open file fail !" <<std::endl;
			}
		}
		initFlag = true;
	}
	else
	{
		//do nothing
	}

	bool ret = false;

	std::string str_1 = str;
	string_replace(str_1, "[", "._");
	string_replace(str_1, "]", "_");
	for (uint32_t i = 0U, size = signalMes.size(); i < size; i++)
	{
		if (str == signalMes[i].name)// Values 1
		{
			ret = true;
			groupIndex = signalMes[i].groupIndex;
			signalIndex = signalMes[i].signalIndex;
			break;
		}
		else if (str_1 == signalMes[i].name)// Values 0
		{
			ret = true;
			groupIndex = signalMes[i].groupIndex;
			signalIndex = signalMes[i].signalIndex;
			break;
		}
		else
		{
			//do nothing
		}
	}

	return ret;
}

static std::vector<uint32_t> groupIndexV;
static std::vector<uint32_t> signalIndexV;
static std::vector<bool> indexValidV;
static uint32_t nowIndex = 0U;
static bool freezeIndex = false;
static void calcIndex(const bool valid, const uint32_t groupIndex, const uint32_t signalIndex)
{
	if(false == freezeIndex)
	{
		if(true == valid)
		{
			groupIndexV.push_back(groupIndex);
			signalIndexV.push_back(signalIndex);
			indexValidV.push_back(true);
		}
		else
		{
			groupIndexV.push_back(0U);
			signalIndexV.push_back(0U);
			indexValidV.push_back(false);
		}
	}
	else
	{
		if(true == valid)
		{
			groupIndexV[nowIndex] = groupIndex;
			signalIndexV[nowIndex] = signalIndex;
			indexValidV[nowIndex] = true;
			std::cout<< "file name = " << __FILE__ <<std::endl;
			std::cout<< "code line = " << std::dec << __LINE__ <<std::endl;
			std::cout<< "calcIndex function error !" <<std::endl;
		}
		else
		{
			//do nothing
		}
	}

	nowIndex++;
}

template<typename T>
static void mappingSignal(const std::string& str, const SimSignalData& nodeData, T* data, const bool isMapping, T defaultValue)
{
	if(true == isMapping)
	{
		if((false == freezeIndex) || (true == freezeIndex && false == indexValidV[nowIndex]))
		{
			uint32_t groupIndex = 0U;
			uint32_t signalIndex = 0U;
			const std::vector<std::string> stringSignal = stringToSignal(str);
			if(1U == stringSignal.size())
			{
				if (true == searchSignal(stringSignal.front(), nodeData, groupIndex, signalIndex))
				{
					*(data) = static_cast<T>(nodeData.signalGroups[groupIndex].signals[signalIndex].dataQueue.back());
					calcIndex(true, groupIndex, signalIndex);
				}
				else
				{
					calcIndex(false, groupIndex, signalIndex);
					std::cout << str << " no exist!" << std::endl;
					std::cout << "file name = " << __FILE__ << std::endl;
					std::cout << "code line = " << std::dec << __LINE__ << std::endl;
				}
			}
			else
			{
				calcIndex(false, groupIndex, signalIndex);
				std::cout << " stringSignal empty!" << std::endl;
				std::cout << "file name = " << __FILE__ << std::endl;
				std::cout << "code line = " << std::dec << __LINE__ << std::endl;
			}
		}
		else
		{
			*(data) = static_cast<T>(nodeData.signalGroups[groupIndexV[nowIndex]].signals[signalIndexV[nowIndex]].dataQueue.back());
			calcIndex(false, 0U, 0U);
		}
	}
	else
	{
		*(data) = defaultValue;
	}
}

void add_VehicleMessage_SimSignal(std::vector<std::string>& simSigNames)
{
}

void init_VehicleMessage_Data(VehicleMessageIF MP_RoadMessage[], const uint32_t size)
{
	const SimSignalData nodeData = SimSignalData();

	mappingSignal("MP_RoadMessage.timeStamp", nodeData, &MP_RoadMessage[0U].timeStamp, false, static_cast<uint64_t>(0));
	mappingSignal("MP_RoadMessage.vehSpd", nodeData, &MP_RoadMessage[0U].vehSpd, false, static_cast<float>(1.0F));

	for(uint32_t i = 1U; i < size; i++)
	{
		MP_RoadMessage[i] = MP_RoadMessage[0U];
	}
}

void mapping_VehicleMessage_Data(const SimSignalData& nodeData, VehicleMessageIF MP_RoadMessage[], const uint32_t index)
{
	nowIndex = 0;
	freezeIndex = true;
}
